#include "ringbuff.h"
#include <stdlib.h>

/* private functions */

/* calculates the end point of the buffer, where new things can be put */
int calc_end(RingBuffer* buffer)
{
    return (buffer->start + buffer->size) % buffer->max_size;
}

/* grows the backing array of the buffer so more things fit */
void grow_buffer(RingBuffer* buffer)
{
    void** new_backing = (void**) malloc(sizeof(void*) * buffer->max_size * GROW_SIZE);
    int i = 0;
    for (; i < buffer->size; i++)
    {
        new_backing[i] = buffer->elements[(buffer->start + i) % buffer->max_size];
    }
    free(buffer->elements);
    buffer->elements = new_backing;
    buffer->max_size *= GROW_SIZE;
}

/* public functions */

RingBuffer* ringbuff_init(int start_size)
{
    RingBuffer* result = (RingBuffer*) malloc(sizeof(RingBuffer));
    result->max_size = start_size;
    result->start = 0;
    result->elements = (void**) malloc(sizeof(void*) * start_size);
    return result;
}

void* ringbuff_get(RingBuffer* buffer)
{
    void* result = NULL;
    if (buffer->size > 0)
    {
        result = buffer->elements[buffer->start];
        buffer->start++;
        buffer->size--;
        if (buffer->start >= buffer->max_size)
        {
            buffer->start = 0;
        }
    }
    return result;
}

int ringbuff_put(RingBuffer* buffer, void* element)
{
    if (element != NULL)
    {
        if (buffer->size == buffer->max_size)
        {
          grow_buffer(buffer);
        }
    
        buffer->elements[calc_end(buffer)] = element;
        buffer->size++;
        return 1;
    }
    return 0;  
}

